package Dm

import (
	"fmt"
	"db2s/ETL"
	"db2s/global"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type Partition struct {
	Schema         string
	Table          string
	SqlExecTimeOut time.Duration
}

func (or Partition) PartitionType(s global.PartitionInput) (p global.PartitionType, err error) {
	var (
		event       = "[PartitionTableType]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	strSql := fmt.Sprintf("select A.OWNER AS \"schema\",A.TABLE_NAME AS \"table\",A.PARTITIONING_TYPE AS \"partitionType\" from ALL_PART_TABLES A WHERE A.OWNER = '%v' AND A.TABLE_NAME = '%v' AND A.PARTITIONING_TYPE IS NOT NULL", schema, table)
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.Map); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	if err = global.MapToStructJson(f1.(map[string]any), &p); err != nil {
		return
	}
	return
}
func (or Partition) SubPartitionType(s global.PartitionInput) (p global.SubPartitionType, err error) {
	var (
		event       = "[PartitionTableType]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	strSql := fmt.Sprintf("SELECT A.OWNER AS \"schema\",A.TABLE_NAME AS \"table\",A.SUBPARTITIONING_TYPE AS \"subPartitionType\" FROM ALL_PART_TABLES A WHERE A.OWNER = '%v' AND A.TABLE_NAME = '%v' AND SUBPARTITIONING_TYPE IS NOT NULL AND SUBPARTITIONING_TYPE != 'NONE'", schema, table)
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.Map); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	if err = global.MapToStructJson(f1.(map[string]any), &p); err != nil {
		return
	}
	return
}
func (or Partition) PartitionColumn(s global.PartitionInput) (p []global.PartitionColumn, err error) {
	var (
		event       = "[PartitionRules]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	strSql := fmt.Sprintf("SELECT C.OWNER AS \"schema\",C.TABLE_NAME AS \"table\",C.COLUMN_NAME AS \"partitionColumnName\",C.DATA_TYPE AS \"partitionColumnType\" FROM ALL_TAB_COLUMNS C LEFT JOIN ALL_PART_KEY_COLUMNS D ON C.OWNER = D.OWNER AND C.TABLE_NAME = D.NAME AND C.COLUMN_NAME = D.COLUMN_NAME WHERE D.OWNER = '%v' AND D.NAME = '%v'", schema, table)
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.SMap); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	for _, v := range f1.([]map[string]any) {
		s1 := global.PartitionColumn{}
		if err = global.MapToStructJson(v, &s1); err != nil {
			return
		}
		p = append(p, s1)
	}
	return
}
func (or Partition) SubPartitionColumn(s global.PartitionInput) (p []global.SubPartitionColumn, err error) {
	var (
		event       = "[PartitionRules]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	strSql := fmt.Sprintf("SELECT C.OWNER AS \"schema\",C.TABLE_NAME AS \"table\",C.COLUMN_NAME AS \"subPartitionColumnName\",C.DATA_TYPE AS \"subPartitionColumnType\" FROM ALL_TAB_COLUMNS C LEFT JOIN ALL_SUBPART_KEY_COLUMNS D ON C.OWNER = D.OWNER AND C.TABLE_NAME = D.NAME AND C.COLUMN_NAME = D.COLUMN_NAME WHERE D.OWNER = '%v' AND D.NAME = '%v'", schema, table)
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.SMap); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}

	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	for _, v := range f1.([]map[string]any) {
		s1 := global.SubPartitionColumn{}
		if err = global.MapToStructJson(v, &s1); err != nil {
			return
		}
		p = append(p, s1)
	}
	return
}

func (or Partition) PartitionName(s global.PartitionInput) (p []global.PartitionName, err error) {
	var (
		event       = "[PartitionTableType]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	strSql := fmt.Sprintf("select A.TABLE_OWNER AS \"schema\",A.TABLE_NAME AS \"table\",A.PARTITION_NAME AS \"partitionName\",A.PARTITION_POSITION AS \"partitionSeq\" from ALL_TAB_PARTITIONS A WHERE A.TABLE_OWNER = '%v' AND A.TABLE_NAME = '%v' AND A.PARTITION_NAME IS NOT NULL", schema, table)
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.SMap); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	if f1 != nil {
		for _, v := range f1.([]map[string]any) {
			var v1 = make(map[string]any)
			for k2, v2 := range v {
				if strings.EqualFold(fmt.Sprintf("%v", reflect.TypeOf(v2)), "godror.Number") {
					v1[k2] = fmt.Sprintf("%v", v2)
				} else {
					v1[k2] = v2
				}
			}
			s1 := global.PartitionName{}
			if err = global.MapToStructJson(v1, &s1); err != nil {
				return
			}
			p = append(p, s1)
		}
	}
	return
}
func (or Partition) SubPartitionName(s global.PartitionInput) (p []global.SubPartitionName, err error) {
	var (
		event       = "[PartitionTableType]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	strSql := fmt.Sprintf("SELECT A.TABLE_OWNER AS \"schema\",A.TABLE_NAME AS \"table\",A.PARTITION_NAME AS \"partitionName\",A.SUBPARTITION_NAME AS \"subPartitionName\",A.SUBPARTITION_POSITION AS \"partitionSeq\" FROM ALL_TAB_SUBPARTITIONS A WHERE A.TABLE_OWNER = '%v' AND A.TABLE_NAME = '%v' AND SUBPARTITION_NAME IS NOT NULL AND SUBPARTITION_NAME != 'NONE'", schema, table)
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.SMap); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	if f1 != nil {
		for _, v := range f1.([]map[string]any) {
			var v1 = make(map[string]any)
			for k2, v2 := range v {
				if strings.EqualFold(fmt.Sprintf("%v", reflect.TypeOf(v2)), "godror.Number") {
					v1[k2] = fmt.Sprintf("%v", v2)
				} else {
					v1[k2] = v2
				}
			}
			s1 := global.SubPartitionName{}
			if err = global.MapToStructJson(v1, &s1); err != nil {
				return
			}
			p = append(p, s1)
		}
	}
	return
}

func (or Partition) PartitionRules(s global.PartitionInput) (p []global.PartitionRules, err error) {
	var (
		event       = "[PartitionRules]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	strSql := fmt.Sprintf("SELECT B.TABLE_OWNER,B.TABLE_NAME,B.PARTITION_NAME AS \"partitionName\",B.HIGH_VALUE AS \"partitionRules\", B.PARTITION_POSITION AS \"partitionSeq\" FROM  ALL_TAB_PARTITIONS B WHERE B.TABLE_OWNER = '%v' AND B.TABLE_NAME = '%v' AND B.PARTITION_NAME IS NOT NULL", schema, table)
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.SMap); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	for _, v := range f1.([]map[string]any) {
		var v1 = make(map[string]any)
		for k2, v2 := range v {
			if strings.EqualFold(fmt.Sprintf("%v", reflect.TypeOf(v2)), "godror.Number") {
				v1[k2] = fmt.Sprintf("%v", v2)
			} else {
				v1[k2] = v2
			}
		}
		s1 := global.PartitionRules{}
		if err = global.MapToStructJson(v1, &s1); err != nil {
			return
		}
		p = append(p, s1)
	}
	return
}
func (or Partition) SubPartitionRules(s global.PartitionInput) (p []global.SubPartitionRules, err error) {
	var (
		event       = "[PartitionRules]"
		f1          any
		execTimeout int64
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	strSql := fmt.Sprintf("SELECT E.TABLE_OWNER AS \"schema\",E.TABLE_NAME AS \"table\",E.PARTITION_NAME AS \"partitionName\",E.SUBPARTITION_NAME AS \"subPartitionName\",E.HIGH_VALUE AS \"subPartitionRules\",E.SUBPARTITION_POSITION AS \"subPartitionSeq\" FROM ALL_TAB_SUBPARTITIONS E WHERE E.TABLE_OWNER='%v' AND E.TABLE_NAME='%v' AND E.PARTITION_NAME IS NOT NULL", schema, table)
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.SMap); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	for _, v := range f1.([]map[string]any) {
		s1 := global.SubPartitionRules{}
		if err = global.MapToStructJson(v, &s1); err != nil {
			return
		}
		p = append(p, s1)
	}
	return
}

func (or Partition) Configuration(s global.PartitionInput) (tpc global.PartitionInfo, err error) {
	var (
		event = "[GetTablePartitionConfiguration]"
	)
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	//获取表的分区类型
	if tpc.PartitionType, err = or.PartitionType(s); err != nil {
		return
	}
	if _, err = or.SubPartitionType(s); err != nil {
		return
	}
	if tpc.PartitionRules, err = or.PartitionRules(s); err != nil {
		return
	}
	if tpc.SubPartitionRules, err = or.SubPartitionRules(s); err != nil {
		return
	}
	if tpc.PartitionColumn, err = or.PartitionColumn(s); err != nil {
		return
	}
	if tpc.SubPartitionColumn, err = or.SubPartitionColumn(s); err != nil {
		return
	}
	return
}

func (or Partition) Sum(s global.PartitionInput) (global.PartitionSummary, error) {
	var (
		event         = "[IfTablePartitionSum]"
		execTimeout   int64
		f1            any
		partitionSum  int64
		err           error
		partitionType string
	)
	p := global.PartitionSummary{}
	pc, _, _, _ := runtime.Caller(1)
	callingFunc := runtime.FuncForPC(pc)
	callFile, callLine := callingFunc.FileLine(pc)
	callFunc := callingFunc.Name()
	callFuncInfo := fmt.Sprintf("Call functions %v Call File %v:%v", callFunc, callFile, callLine)
	vlog = fmt.Sprintf("(%d) %v %v Start checking whether table %v.%v exists.", s.LogSeq, callFuncInfo, event, or.Schema, or.Table)
	WLog.Debug(vlog)
	schema := s.Schema
	table := s.Table
	strSql := fmt.Sprintf(" SELECT * FROM (SELECT PARTITIONING_TYPE || ',' || SUBPARTITIONING_TYPE AS \"partitionType\" FROM ALL_PART_TABLES WHERE OWNER='%v' AND TABLE_NAME='%v') A, (SELECT SUM(DECODE(COMPOSITE,'YES',SUBPARTITION_COUNT,1)) AS \"sum\" FROM all_tab_partitions WHERE TABLE_OWNER='%v' AND TABLE_NAME = '%v') B", schema, table, schema, table)
	active := ETL.InstanceActiveS{DBType: DBType, DB: s.Db, StopTime: or.SqlExecTimeOut, SqlMode: true}
	if execTimeout, f1, err = active.SqlQuery(strSql, ETL.Map); err != nil {
		vlog = fmt.Sprintf("(%d) %v %v The execution of a sql statement failed. sql is {%v},error is {%v}", s.LogSeq, callFuncInfo, event, strSql, err)
		WLog.Error(vlog)
		return p, err
	}
	vlog = fmt.Sprintf("(%d) %v %v A sql statement was executed successfully. sql is {%v}, exec timeout is {%vms}", s.LogSeq, callFuncInfo, event, strSql, execTimeout)
	WLog.Debug(vlog)
	if f1 != nil {
		f2 := f1.(map[string]interface{})
		if v, ok := f2["sum"]; ok {
			if d, err1 := strconv.ParseInt(fmt.Sprintf("%s", v), 10, 64); err1 == nil {
				if d > 0 {
					partitionSum = d
				}
			} else {
				vlog = fmt.Sprintf("(%d) %v %s Table %v.%v row count conversion failed. data is %s, error is %s", s.LogSeq, callFuncInfo, event, or.Schema, or.Table, v, err)
				WLog.Warn(vlog)
			}
		}
		if v, ok := f2["partitionType"]; ok {
			partitionType = fmt.Sprintf("%v", v)
		}
	}
	WLog.Warn(fmt.Sprintf("(%d) %v %s Check whether table a exists or not is completed. result is {%v}", s.LogSeq, callFuncInfo, event, "table not is Exist!"))
	p.Sum = partitionSum
	p.PartitionType = partitionType
	return p, nil
}
